//bange_console.cpp
//Copyright (C) 2010-2011 Oscar (.teri) Triano

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <bange_console.hpp>

bange::console::entry::entry(const char *text):sf::String(text){
	this->icursor = 0;
}

#ifdef DEBUG_ENTRY_DESTRUCTOR
bange::console::entry::~entry(){
	std::cout << "Destroying entry: " << this << std::endl;
}
#endif

void bange::console::entry::AddChar(sf::Uint32 character){
	sf::Unicode::Text text = this->GetText();
	sf::Unicode::UTF32String thestring = sf::Unicode::UTF32String(text); 
	thestring.insert(this->icursor, 1, character);
	this->SetText(thestring);
	this->icursor += 1;
}

void bange::console::entry::RemoveChar(){
	sf::Unicode::Text text = this->GetText();
	sf::Unicode::UTF32String thestring = sf::Unicode::UTF32String(text);
	if (icursor-1 < 0){
		return;}
	thestring.erase(this->icursor-1, 1);
	this->SetText(thestring);
	if (this->icursor != 0){
		this->icursor -= 1;}
}

void bange::console::entry::MoveCursor(int offset){
	if ( (icursor == 0 && offset < 0) \
	|| (icursor == (sf::Unicode::UTF32String(this->GetText()).length()) && offset > 0) ){
		return;}
	icursor += offset;
}

const char *bange::console::entry::GetString(){
	sf::Unicode::Text text = this->GetText();
	std::string string = std::string(text);
	return string.c_str();
}

sf::Vector2f bange::console::entry::GetCursorPosition(){
	return this->GetCharacterPos(this->icursor);
}

bange::console::console(){
	this->fontsize = 16.f;
	bange::console::entry *entry;
	int times = 480.f / this->fontsize;
	this->dbentries = (480.f / times)-1;
	this->icursor = times-1;
	for (int i = 0; i < times; i += 1){
		entry = new bange::console::entry("");
		entry->SetSize(this->fontsize);
		this->entries.push_front(entry);
	}
	this->ResetPositionEntries();
	this->background = sf::Shape::Rectangle(0.f, 0.f, 640.f, 480.f, sf::Color(0, 0, 0, 128));
	currententry = entries.end()-1;
	this->cursor = sf::Shape::Line(0.f, 0, 0.f, fontsize, 2.f, sf::Color(255, 255, 255));
	this->ResetPositionCursor();
}

bange::console::~console(){
	bange::console::entry *entry;
	std::deque<bange::console::entry *>::iterator aentry;
	for(aentry = this->entries.begin(); aentry != this->entries.end(); aentry++){
		delete (*aentry);
	}
	this->entries.clear();
	#ifdef CONSOLE_DEBUG
	std::cout << "Console deleted" << std::endl;
	#endif
}

void bange::console::MoveCursorThroughEntries(int offset){
	if ((offset < 0 and this->currententry == this->entries.begin()) \
	|| (offset > 0 and this->currententry == this->entries.end()-1) ){
		return;}
	advance(this->currententry, offset);
	if (offset < 0){
		icursor -= 1;}
	else if (offset > 0){
		icursor += 1;}
	this->ResetPositionCursor();
}

void bange::console::MoveCursor(int offset){
	(*currententry)->MoveCursor(offset);
	this->ResetPositionCursor();
}

void bange::console::AddChar(sf::Int32 character){
	if (currententry != entries.end()-1){
		return;}
	(*currententry)->AddChar(character);
	this->ResetPositionCursor();
}

void bange::console::RemoveChar(){
	if (currententry != entries.end()-1){
		return;}
	(*currententry)->RemoveChar();
	this->ResetPositionCursor();
}

void bange::console::AddEntry(const char *string){
	bange::console::entry *newentry = new bange::console::entry(string);
	delete (*entries.begin());
	entries.pop_front();
	entries.push_back(newentry);
	newentry->SetSize(this->fontsize);
	currententry = entries.end()-1;
	this->ResetPositionEntries();
	this->ResetPositionCursor();
}

const char *bange::console::GetString(){
	if (currententry != entries.end()-1){
		return NULL;}
	return (*currententry)->GetString();
}

void bange::console::Draw(sf::RenderWindow &renderwindow){
	renderwindow.Draw(background);
	std::deque<bange::console::entry *>::iterator aentry;
	sf::Vector2f pos;
	sf::View &view = renderwindow.GetDefaultView();
	renderwindow.SetView(view);
	float move_x;
	for(aentry = entries.begin(); aentry != entries.end(); aentry++){		
		pos = (*aentry)->GetCursorPosition();
		move_x = static_cast<int>(pos.x / 640.f)*640.f;
		view.Move(move_x, 0.f);
		renderwindow.Draw(*(*aentry));
		view.Move(-move_x, 0.f);
	}
	pos = cursor.GetPosition();
	move_x = static_cast<int>(pos.x / 640.f)*640.f;
	view.Move(move_x, 0.f);
	renderwindow.Draw(cursor);
	view.Move(-move_x, 0.f);
}

void bange::console::ResetPositionEntries(){
	std::deque<bange::console::entry *>:: iterator aentry;
	sf::Vector2f position;
	position.x = 8.f;
	for(aentry = this->entries.begin(); aentry != this->entries.end(); aentry++, position.y += this->dbentries){
		(*aentry)->SetPosition(position);
	}
}

void bange::console::ResetPositionCursor(){
	sf::Vector2f position;
	position = (*currententry)->GetCursorPosition();
	position.x += 8.f;
	position.y = dbentries*icursor;
	cursor.SetPosition(position);
}
